﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;

namespace DynamicGeometry
{
    public class FunctionGraph : Curve, ILinearFigure
    {
        public string c_store_id { get; set; }
        public string c_guid { get; set; }

        public string c_type { get; set; }
        public bool c_is_modify { get; set; }
        const int count = 80;

        public FunctionGraph()
        {
            for (int i = 0; i < count; i++)
            {
                pathSegments.Add(new LineSegment());
            }
        }

        private Func<double, double> mFunction = x => 0;
        public Func<double, double> Function
        {
            get
            {
                return mFunction;
            }
            private set
            {
                if (value != null)
                {
                    mFunction = value;
                    UpdateVisual();
                }
            }
        }

        private string mFunctionText;
        [PropertyGridVisible]
        [PropertyGridName("f(x) = ")]
        public string FunctionText
        {
            get
            {
                return mFunctionText;
            }
            set
            {
                if (ExpressionCompiler.Singleton != null)
                {
                    var func = ExpressionCompiler.Singleton.Compile(value);
                    if (func != null)
                    {
                        mFunctionText = value;
                        Function = func;
                    }
                }
            }
        }

        double CallFunction(double parameter)
        {
            try
            {
                return Function(parameter);
            }
            catch (Exception)
            {
                return 0;
            }
        }

        public override IList<Point> GetPoints()
        {
            List<Point> result = new List<Point>(count);

            CoordinateSystem coordinates = Drawing.CoordinateSystem;
            double minX = coordinates.MinimalVisibleX;
            double maxX = coordinates.MaximalVisibleX;

            var step = (maxX - minX) / count;
            for (double x = minX; x < maxX; x += step)
            {
                double y = CallFunction(x);
                result.Add(new Point(x, y));
            }

            result.Add(new Point(maxX, CallFunction(maxX)));

            return result;
        }

        public double GetNearestParameterFromPoint(Point point)
        {
            return point.X;
        }

        public Point GetPointFromParameter(double parameter)
        {
            return new Point(parameter, CallFunction(parameter));
        }

        public Tuple<double, double> GetParameterDomain()
        {
            CoordinateSystem coordinates = Drawing.CoordinateSystem;
            return Tuple.Create(coordinates.MinimalVisibleX, coordinates.MaximalVisibleX);
        }

        public override IFigure HitTest(Point point)
        {
            return this.IsPointWithinTolerance(point) ? this : null;
        }
    }
}
